package com.whale.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.xiaoymin.knife4j.core.util.CollectionUtils;
import com.whale.WebSocket.WebSocketServer;
import com.whale.constant.MessageConstant;
import com.whale.context.BaseContext;
import com.whale.dto.*;
import com.whale.entity.Reserve;
import com.whale.entity.ReserveDetail;
import com.whale.entity.User;
import com.whale.exception.OrderBusinessException;
import com.whale.exception.VenueOccupyExistException;
import com.whale.mapper.*;
import com.whale.result.PageResult;
import com.whale.service.ReserveService;
import com.whale.utils.WeChatPayUtil;
import com.whale.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.ListUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ReserveServiceImpl implements ReserveService {

    @Autowired
    private ReserveMapper reserveMapper;
    @Autowired
    private ReserveDetailMapper reserveDetailMapper;

    @Autowired
    private WeChatPayUtil weChatPayUtil;
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private WebSocketServer webSocketServer;

    @Autowired
    private VenueOccupyMapper venueOccupyMapper;
    /**
     * 用户预约
     * @param reserveSubmitDTO
     * @return
     */
    @Transactional
    public ReserveSubmitVO submitReserve(ReserveSubmitDTO reserveSubmitDTO) {

        Long userId=BaseContext.getCurrentId();
        log.info("预约的用户为:{}",userId);

        //判断预约场地是否被占用
        List<ReserveDetail> details = venueOccupyMapper.getDetaillsit();
        for(ReserveDetail detail:reserveSubmitDTO.getReserveDetailList()){
            for(ReserveDetail reserve :details){
                if(detail.equals(reserve)){
                    throw new VenueOccupyExistException(MessageConstant.VENUE_OCCUPY);
                }
            }
        }


        //向预约表插入1条数据
        Reserve reserve=new Reserve();
        BeanUtils.copyProperties(reserveSubmitDTO,reserve);
        reserve.setUserId(userId);
        reserve.setPhone(userMapper.getById(userId).getPhone());
        reserve.setReserveTime(LocalDateTime.now());
        reserve.setNumber(String.valueOf(System.currentTimeMillis()));
        reserve.setStatus(Reserve.PENDING_PAYMENT);
        reserve.setPayStatus(Reserve.UN_PAID);

        reserveMapper.insert(reserve);


         //向预约明细表和场地占用表中插入n条数据
        List<ReserveDetail> reserveDetails=new ArrayList<>();
        for(ReserveDetail list: reserveSubmitDTO.getReserveDetailList()){
            ReserveDetail reserveDetail = new ReserveDetail();
            BeanUtils.copyProperties(list,reserveDetail);
            reserveDetail.setReserveId(reserve.getId());
            reserveDetail.setType(reserveSubmitDTO.getType());
            reserveDetails.add(reserveDetail);


        }
        reserveDetailMapper.insertBetch(reserveDetails);
        venueOccupyMapper.insertBetch(reserveDetails);

        //封装VO返回结果
        ReserveSubmitVO reserveSubmitVO = new ReserveSubmitVO();
        reserveSubmitVO.setReserveTime(LocalDateTime.now());
        reserveSubmitVO.setReserveNumber(reserve.getNumber());
        reserveSubmitVO.setReserveAmount(reserve.getAmount());
        reserveSubmitVO.setId(reserve.getId());
        return reserveSubmitVO;
    }
    /**
     * 订单支付
     *
     * @param reservePaymentDTO
     * @return
     */
    public ReservePaymentVO payment(ReservePaymentDTO reservePaymentDTO) throws Exception {
        // 当前登录用户id
        Long userId = BaseContext.getCurrentId();
        User user = userMapper.getById(userId);

        //调用微信支付接口，生成预支付交易单
        JSONObject jsonObject = weChatPayUtil.pay(
                reservePaymentDTO.getOrderNumber(), //商户订单号
                //TODO
                new BigDecimal(String.valueOf(reserveMapper.getByNumber(reservePaymentDTO.getOrderNumber()).getAmount())), //支付金额，单位 元
                "鲸落花园订单", //商品描述
                user.getOpenid() //微信用户的openid
        );

        if (jsonObject.getString("code") != null && jsonObject.getString("code").equals("ORDERPAID")) {
            throw new OrderBusinessException("该订单已支付");
        }

        ReservePaymentVO reservePaymentVO = jsonObject.toJavaObject(ReservePaymentVO.class);
        reservePaymentVO.setPackageStr(jsonObject.getString("package"));

        return reservePaymentVO;
    }

    /**
     * 支付成功，修改预约状态
     *
     * @param outTradeNo
     */
    public void paySuccess(String outTradeNo) {

        // 根据预约号查询预约
        Reserve reserveDB = reserveMapper.getByNumber(outTradeNo);

        // 根据预约id更新预约的状态、支付方式、支付状态、结账时间
        Reserve reserve = Reserve.builder()
                .id(reserveDB.getId())
                .status(Reserve.COMPLETED)
                .payStatus(Reserve.PAID)
                .checkoutTime(LocalDateTime.now())
                .build();
        reserveMapper.update(reserve);
        //通过webSocket向商家客户端浏览器推送消息type orderId content
        Map map=new HashMap();
        map.put("type",1);
        map.put("reserveId",reserve.getId());
        map.put("content","预约号:"+reserve.getNumber());
        String json = JSON.toJSONString(map);
        webSocketServer.sendToAllClient(json);

    }

    /**
     * 用户端预约分页查询
     *
     * @param pageNum
     * @param pageSize
     * @param status
     * @return
     */
    public PageResult pageQuery4User(int pageNum, int pageSize, Integer status) {
        // 设置分页
        PageHelper.startPage(pageNum, pageSize);

        ReservePageQueryDTO reservePageQueryDTO = new ReservePageQueryDTO();
        reservePageQueryDTO.setUserId(BaseContext.getCurrentId());
        reservePageQueryDTO.setStatus(status);
        // 分页条件查询
        Page<Reserve> page = reserveMapper.pageQuery(reservePageQueryDTO);
        List<ReserveVO> list = new ArrayList();
        // 查询出预约明细，并封装入ReserveVO进行响应
        if (page != null && page.getTotal() > 0) {
            for (Reserve reserve : page) {
                Long reserveId = reserve.getId();// 订单id
                // 查询预约明细
                List< ReserveDetail>  reserveDetail = reserveDetailMapper.getByReserveId(reserveId);
                ReserveVO reserveVO = new ReserveVO();
                BeanUtils.copyProperties(reserve, reserveVO);
                reserveVO.setReserveDetailList(reserveDetail);
                list.add(reserveVO);
            }
        }
        return new PageResult(page.getTotal(), list);
    }

    /**
     * 查询预约详情
     *
     * @param id
     * @return
     */
    public ReserveVO details(Long id) {
        // 根据id查询预约
        Reserve reserve = reserveMapper.getById(id);
        // 查询该预约对应的时间场地号明细
        List<ReserveDetail> reserveDetailList = reserveDetailMapper.getByReserveId(reserve.getId());

        // 将该订单及其详情封装到reserveVO并返回
        ReserveVO reserveVO = new ReserveVO();
        BeanUtils.copyProperties(reserve, reserveVO);
        reserveVO.setReserveDetailList(reserveDetailList);

        return reserveVO;
    }

    /**
     * 用户取消预约
     *
     * @param id
     */
    public void userCancelById(Long id) throws Exception {
        // 根据id查询预约
        Reserve reserveDB = reserveMapper.getById(id);

        // 校验预约是否存在
        if (reserveDB == null) {
            throw new OrderBusinessException(MessageConstant.RESERVE_NOT_FOUND);
        }

        //预约状态 1待付款 2已完成 3已取消
        if (reserveDB.getStatus() > 1) {
            throw new OrderBusinessException(MessageConstant.RESERVE_STATUS_ERROR);
        }

        Reserve reserve = new Reserve();
        reserve.setId(reserveDB.getId());

        // 更新预约状态、取消原因、取消时间
        reserve.setStatus(Reserve.CANCELLED);
        reserve.setCancelReason("用户取消");
        reserve.setCancelTime(LocalDateTime.now());
        reserveMapper.update(reserve);
        // 从场地占用表中删除占用的预约
        venueOccupyMapper.deleteByReserveId(id);
    }
}
